/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package View;

import Control.DESForecasting;
import Control.DMAForecasting;
import Control.ESForecasting;
import Control.ForecastResults;
import Control.HoltWintersMultiplicativeForecasting;
import Control.SMAForecasting;
import Control.Validator;
import Persistence.PDFDocument;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.swing.JOptionPane;

/**
 *
 * @author Juan
 */
public class GUI extends javax.swing.JFrame {

    private List<Double> inputs = new ArrayList<>();
    private String output = "Prediction";
    private final SMAForecasting smaf = new SMAForecasting();
    private final DMAForecasting dmaf = new DMAForecasting();
    private final ESForecasting esf = new ESForecasting();
    private final DESForecasting desf = new DESForecasting();
    private final HoltWintersMultiplicativeForecasting holt = new HoltWintersMultiplicativeForecasting();

    /**
     * Creates new form GUI
     */
    public GUI() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        txtFieldIData = new javax.swing.JTextField();
        btnAdd = new javax.swing.JButton();
        btnDelete = new javax.swing.JButton();
        btnDeleteAll = new javax.swing.JButton();
        btnForecast = new javax.swing.JButton();
        txtFieldIValues = new javax.swing.JTextField();
        savePDF = new javax.swing.JCheckBox();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        txtAreaOutput = new javax.swing.JTextArea();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Virtual weather forecaster");

        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Data Input"));
        jPanel1.setName(""); // NOI18N

        jLabel1.setText("Weather Report (°C):");

        jLabel2.setText("Values to Forecast:");

        txtFieldIData.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                txtFieldIDataActionPerformed(evt);
            }
        });

        btnAdd.setText("Add");
        btnAdd.setToolTipText("");
        btnAdd.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnAddActionPerformed(evt);
            }
        });

        btnDelete.setText("Delete Last");
        btnDelete.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDeleteActionPerformed(evt);
            }
        });

        btnDeleteAll.setText("Delete All");
        btnDeleteAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnDeleteAllActionPerformed(evt);
            }
        });

        btnForecast.setText("Forecast");
        btnForecast.setToolTipText("");
        btnForecast.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnForecastActionPerformed(evt);
            }
        });

        txtFieldIValues.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                txtFieldIValuesActionPerformed(evt);
            }
        });

        savePDF.setText("Save to PDF");

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addGap(52, 52, 52)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(txtFieldIData, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(txtFieldIValues, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addGap(52, 52, 52))
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(btnAdd)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btnDelete)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btnDeleteAll)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(savePDF)
                    .addComponent(btnForecast))
                .addGap(20, 20, 20))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(19, 19, 19)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(txtFieldIData, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(txtFieldIValues, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 13, Short.MAX_VALUE)
                .addComponent(savePDF)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnAdd)
                    .addComponent(btnDelete)
                    .addComponent(btnDeleteAll)
                    .addComponent(btnForecast))
                .addContainerGap())
        );

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Forecasting Results"));

        txtAreaOutput.setEditable(false);
        txtAreaOutput.setColumns(20);
        txtAreaOutput.setRows(5);
        jScrollPane1.setViewportView(txtAreaOutput);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 370, Short.MAX_VALUE)
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 123, Short.MAX_VALUE)
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void txtFieldIDataActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtFieldIDataActionPerformed
    }//GEN-LAST:event_txtFieldIDataActionPerformed

    private void txtFieldIValuesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtFieldIValuesActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_txtFieldIValuesActionPerformed

    private void btnAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddActionPerformed
        String value = txtFieldIData.getText();

        try{
            inputs.add(Double.valueOf(value));
        }catch(NumberFormatException ex){
            notifyUser("Invalid input.");
        }
      
        formatInput(inputs);
        btnForecast.setEnabled(true);
    }//GEN-LAST:event_btnAddActionPerformed

    private void btnDeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeleteActionPerformed
        if (inputs.size() > 0) {
            inputs.remove(inputs.size() - 1); // remove last element of the list.
            formatInput(inputs);
        }
        btnForecast.setEnabled(true);


    }//GEN-LAST:event_btnDeleteActionPerformed

    private void btnDeleteAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDeleteAllActionPerformed
        inputs.clear(); // remove all elements in the list
        formatInput(inputs);
        btnForecast.setEnabled(true);
    }//GEN-LAST:event_btnDeleteAllActionPerformed

    private void btnForecastActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnForecastActionPerformed
        ArrayList<ForecastResults> results = new ArrayList();

        ForecastResults smaResults = new ForecastResults();
        ForecastResults dmaResults = new ForecastResults();
        ForecastResults esResults = new ForecastResults();
        ForecastResults desResults = new ForecastResults();
        ForecastResults holtResults = new ForecastResults();

        Double[] values = new Double[inputs.size()];
        values = inputs.toArray(values);

        try{
        
        smaResults.setInputs(values);
        smaResults.setOutputs(smaf.forecast(values));

        dmaResults.setInputs(values);
        dmaResults.setOutputs(dmaf.forecast(values));

        esResults.setInputs(values);
        esResults.setOutputs(esf.forecast(values));

        desResults.setInputs(values);
        desResults.setOutputs(desf.forecast(values));
        
        holtResults.setInputs(values);
        holtResults.setOutputs(holt.forecast(values));
        } catch(IllegalArgumentException ex){
            notifyUser(ex.getMessage());
            return;
        }
        
        results.add(smaResults);
        results.add(dmaResults);
        results.add(esResults);
        results.add(desResults);
        results.add(holtResults);
        
        ForecastResults minResult = Validator.getMin(results);
        minResult.getOutputs();
        
        Double error = Validator.getMinErr();
        
        Integer lenght;
        
        try{
            lenght = Integer.valueOf(txtFieldIValues.getText());
        }catch(NumberFormatException ex){
            notifyUser("Invalid input. You must enter a corret value to forecast.");
            return;
        }
        
        if(!Validator.validate(lenght, minResult)){
            notifyUser("The predictions cannot be greater than the inputs");
            return;
        }
        
        output = txtAreaOutput.getText() + "\nForecast:" + formatText(minResult.getOutputs(), lenght,error);
        
        if(savePDF.isSelected()){
            PDFDocument.createDocument("Forecast", formatText(minResult.getOutputs(), lenght, error));
            notifyUser("The Forecast has been saved as 'Forecast.pdf'.");
        }
        
        txtAreaOutput.setText(output);
        btnForecast.setEnabled(false);

    }//GEN-LAST:event_btnForecastActionPerformed

    private void notifyUser(String notification) {
        JOptionPane.showMessageDialog(rootPane, notification);
    }

    // This method formats the user input
    private void formatInput(List<Double> inputs) {
        String formattedInputs = "Input temperatures:";
        
        for(Double value: inputs){
            formattedInputs = formattedInputs + "\n" + value.toString() + " °C";
        }

        txtAreaOutput.setText(formattedInputs + "\n");
    }

    // This method formats the forecasting results
    private String formatText(Double[] values, Integer lenght, Double val) {

        String output = "";
        DecimalFormat df = new DecimalFormat("#.00");
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yyyy");
        
        for (int i = 0; i < lenght; ++i) {

            // This calculates the dates of next days
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DATE, i + 1);
            String dates = dateFormat.format(calendar.getTime());

            output = output + "\n" + dates + " :      " + String.valueOf(df.format(values[i])) + " °C";
        }
        output+="\n Error: "+String.valueOf(df.format(val))+" %";
        return output;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new GUI().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnAdd;
    private javax.swing.JButton btnDelete;
    private javax.swing.JButton btnDeleteAll;
    private javax.swing.JButton btnForecast;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JCheckBox savePDF;
    private javax.swing.JTextArea txtAreaOutput;
    private javax.swing.JTextField txtFieldIData;
    private javax.swing.JTextField txtFieldIValues;
    // End of variables declaration//GEN-END:variables
}
